<?php

namespace app\api\logic;

use app\common\exception\BusinessException;
use app\common\helper\WxHelper;
use app\common\model\App;
use app\common\service\OssService;
use app\common\service\WxService;
use think\facade\Cache;

class Sso
{
    /**
     * checkAppIdAndGetInfo
     * @param $appId
     * @return array
     * @throws
     */
    private function checkAppIdAndGetInfo($appId): array
    {
        $where = ['app_id' => $appId];
        $appInfo = app(App::class)->where($where)->find();
        if (!$appInfo) {
            throw new BusinessException('租户信息不存在');
        }
        $appInfo = $appInfo->toArray();
        if (!$appInfo['app_private_key'] || !$appInfo['app_public_key']) {
            throw new BusinessException('租户通讯安全未配置');
        }
        return $appInfo;
    }

    /**
     * createLoginQr
     * @param $param
     * @return array
     * @throws BusinessException
     */
    public function createLoginQr($param): array
    {
        // 检查appId是否存在
        $appId = getAppId();
        if (!$appId) {
            $appId = $param['appId'] ?? '';
        }
        if (!$appId) {
            throw new BusinessException('租户编号不得为空');
        }

        // 检查租户信息
        $this->checkAppIdAndGetInfo($appId);

        // 生成请求id
        $reqId = $this->buildReqId($appId);

        // 生成扫码地址
        $reqQr = $this->buildQr($appId, $reqId);

        // 返回
        return [
            'reqId' => $reqId,
            'reqQr' => $reqQr,
        ];
    }

    /**
     * checkLoginQr
     * @param $param
     * @return array
     */
    public function checkLoginQr($param): array
    {
        // 检查appId是否存在
        $reqId = $param['reqId'];

        // 读取缓存信息
        $cacheKey = $reqId;
        $cacheData = Cache::get($cacheKey);

        // 返回
        return [
            'status' => (bool)$cacheData,
            'encryptData' => $cacheData ?: '',
        ];
    }

    /**
     * confirmLoginQr
     * @param $param
     * @throws BusinessException
     */
    public function confirmLoginQr($param)
    {
        // 提取参数
        $reqId = $param['reqId'];
        $userId = $param['userId'];
        if (!$userId) {
            throw new BusinessException('请先登录');
        }

        // 检查appId是否存在
        $appId = getAppId();
        if (!$appId) {
            $appId = $param['appId'] ?? '';
        }
        if (!$appId) {
            throw new BusinessException('租户编号不得为空');
        }

        // 通过请求id查询appId信息,公钥加密信息
        $appInfo = $this->checkAppIdAndGetInfo($appId);

        // 生成加密信息并保存到缓存
        $encryptData = rsaEncrypt($userId, $appInfo['app_public_key']);
        $cacheKey = $reqId;
        if (!Cache::set($cacheKey, $encryptData, 120)) {
            throw new BusinessException('安全信息储存失败');
        }
    }

    /**
     * buildReqId
     * @param string $appId
     * @return string
     */
    private function buildReqId(string $appId): string
    {
        return md5($appId . uniqid());
    }

    /**
     * buildQr
     * @param $appId
     * @param $reqId
     * @return string
     * @throws
     */
    private function buildQr($appId, $reqId): string
    {
        // 设置路径|场景
        $path = 'pages/index/sso/sso';
        $scene = $reqId;

        // 获取accessToken
        $access_token = (new WxService())->setAppId($appId)->getAccessToken();

        // 生成路径地址
        $binData = WxHelper::createWxQrcode($access_token, $path, $scene);

        // 上传文件到Oss文件服务器
        $app = 'learnAppUserSso';
        $suffix = 'image/png';
        $ossService = new OssService($app);
        return $ossService->uploadBin($binData, $suffix);
    }
}